import hikyuu as hku
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import os

class HikyuuAnalyzer:
    """使用Hikyuu进行量化分析"""
    
    def __init__(self, config):
        self.config = config
        
        # 初始化Hikyuu
        if os.path.exists(config.get('hikyuu_config', 'hikyuu.ini')):
            hku.init(config.get('hikyuu_config', 'hikyuu.ini'))
        else:
            # 使用默认配置初始化
            hku.sm.init()
            
        self.strategies = {}
    
    def _convert_code(self, tushare_code):
        """将Tushare代码转换为Hikyuu代码"""
        if '.' in tushare_code:
            code, market = tushare_code.split('.')
            if market == 'SH':
                return f"sh{code}"
            else:
                return f"sz{code}"
        return tushare_code
    
    def get_stock(self, stock_code):
        """获取股票对象"""
        hikyuu_code = self._convert_code(stock_code)
        return hku.Stock(hikyuu_code)
    
    def calculate_indicators(self, stock_code, start_date=None, end_date=None):
        """计算技术指标"""
        stock = self.get_stock(stock_code)
        
        # 设置日期范围
        if start_date is None:
            start_date = (datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d')
        if end_date is None:
            end_date = datetime.now().strftime('%Y-%m-%d')
            
        # 获取K线数据
        kdata = stock.get_kdata(start_date, end_date)
        
        # 计算常用指标
        close = kdata.close
        
        # 计算MA指标
        ma5 = hku.MA(close, 5)
        ma10 = hku.MA(close, 10)
        ma20 = hku.MA(close, 20)
        ma30 = hku.MA(close, 30)
        ma60 = hku.MA(close, 60)
        
        # 计算MACD指标
        macd = hku.MACD(close)
        macd_dif = macd.get_result(0)
        macd_dea = macd.get_result(1)
        macd_bar = macd.get_result(2)
        
        # 计算KDJ指标
        kdj = hku.KDJ(kdata)
        k = kdj.get_result(0)
        d = kdj.get_result(1)
        j = kdj.get_result(2)
        
        # 计算RSI指标
        rsi6 = hku.RSI(close, 6)
        rsi12 = hku.RSI(close, 12)
        rsi24 = hku.RSI(close, 24)
        
        # 计算布林带
        boll = hku.BOLL(close)
        boll_up = boll.get_result(0)
        boll_mid = boll.get_result(1)
        boll_low = boll.get_result(2)
        
        # 转换为DataFrame
        result = pd.DataFrame({
            'date': kdata.datetime,
            'open': kdata.open,
            'high': kdata.high,
            'low': kdata.low,
            'close': kdata.close,
            'volume': kdata.volume,
            'amount': kdata.amount,
            'ma5': ma5,
            'ma10': ma10,
            'ma20': ma20,
            'ma30': ma30,
            'ma60': ma60,
            'macd_dif': macd_dif,
            'macd_dea': macd_dea,
            'macd_bar': macd_bar,
            'k': k,
            'd': d,
            'j': j,
            'rsi6': rsi6,
            'rsi12': rsi12,
            'rsi24': rsi24,
            'boll_up': boll_up,
            'boll_mid': boll_mid,
            'boll_low': boll_low
        })
        
        # 填充缺失值
        result = result.fillna(0)
        
        return result
    
    def create_strategy(self, stock_code, strategy_type='ma_cross'):
        """创建交易策略"""
        stock = self.get_stock(stock_code)
        
        # 创建交易系统
        sys = hku.System()
        sys.set_stock(stock)
        
        if strategy_type == 'ma_cross':
            # 使用均线交叉策略
            ma_short = hku.MA(5)
            ma_long = hku.MA(20)
            
            # 买入条件：短期均线上穿长期均线
            buy_signal = hku.CROSS(ma_short, ma_long)
            sys.set_buy_signal(buy_signal)
            
            # 卖出条件：短期均线下穿长期均线
            sell_signal = hku.CROSS(ma_long, ma_short)
            sys.set_sell_signal(sell_signal)
            
        elif strategy_type == 'kdj_cross':
            # 使用KDJ交叉策略
            kdj = hku.KDJ()
            k = kdj.get_result(0)
            d = kdj.get_result(1)
            
            # 买入条件：K线上穿D线且K值小于50
            buy_signal = hku.CROSS(k, d) & (k < 50)
            sys.set_buy_signal(buy_signal)
            
            # 卖出条件：K线下穿D线或K值大于80
            sell_signal = hku.CROSS(d, k) | (k > 80)
            sys.set_sell_signal(sell_signal)
            
        elif strategy_type == 'macd_cross':
            # 使用MACD交叉策略
            macd = hku.MACD()
            dif = macd.get_result(0)
            dea = macd.get_result(1)
            
            # 买入条件：DIF上穿DEA
            buy_signal = hku.CROSS(dif, dea)
            sys.set_buy_signal(buy_signal)
            
            # 卖出条件：DIF下穿DEA
            sell_signal = hku.CROSS(dea, dif)
            sys.set_sell_signal(sell_signal)
            
        else:
            raise ValueError(f"不支持的策略类型: {strategy_type}")
        
        # 仓位管理
        tm = hku.MoneyManagerBase()
        sys.set_money_manager(tm)
        
        # 设置账户初始资金为10万
        sys.set_initial_cash(100000)
        
        # 保存策略
        self.strategies[stock_code] = {
            'system': sys,
            'type': strategy_type
        }
        
        return sys
    
    def backtest(self, stock_code, start_date=None, end_date=None, strategy_type='ma_cross'):
        """回测策略"""
        # 确保策略存在
        if stock_code not in self.strategies or self.strategies[stock_code]['type'] != strategy_type:
            self.create_strategy(stock_code, strategy_type)
        
        # 获取系统
        sys = self.strategies[stock_code]['system']
        
        # 设置回测日期
        if start_date is None:
            start_date = (datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d')
        if end_date is None:
            end_date = datetime.now().strftime('%Y-%m-%d')
        
        # 运行回测
        sys.run_param(start_date, end_date)
        
        # 获取回测结果
        tm = hku.TradingManager(start_date, end_date)
        tm.add_strategy(sys)
        tm.run()
        
        # 生成回测报告
        report = tm.report()
        trade_list = tm.trade_list()
        
        # 转换为DataFrame
        trades_df = pd.DataFrame({
            'stock': [t.stock.market_code for t in trade_list],
            'datetime': [t.datetime.to_str() for t in trade_list],
            'business': [t.business for t in trade_list],
            'price': [t.price for t in trade_list],
            'volume': [t.volume for t in trade_list],
            'cost': [t.cost for t in trade_list],
            'stoploss': [t.stoploss for t in trade_list],
        })
        
        return {
            'report': report,
            'trades': trades_df,
            'summary': {
                'start_date': start_date,
                'end_date': end_date,
                'total_return': report.total_returns * 100,
                'annual_return': report.annual_returns * 100,
                'max_drawdown': report.max_drawdown * 100,
                'win_rate': report.win_rate * 100,
                'total_trades': report.total_num,
                'win_trades': report.win_num,
                'lose_trades': report.lose_num,
                'sharpe_ratio': report.sharpe,
            }
        }
    
    def analyze_stock(self, stock_code):
        """分析股票并生成报告"""
        # 计算技术指标
        indicators = self.calculate_indicators(stock_code)
        
        # 获取最新数据
        latest = indicators.iloc[-1]
        
        # 判断趋势
        if latest['ma5'] > latest['ma10'] > latest['ma20']:
            trend = "上升趋势"
        elif latest['ma5'] < latest['ma10'] < latest['ma20']:
            trend = "下降趋势"
        else:
            trend = "盘整趋势"
        
        # 判断MACD信号
        if latest['macd_bar'] > 0 and indicators.iloc[-2]['macd_bar'] <= 0:
            macd_signal = "金叉，买入信号"
        elif latest['macd_bar'] < 0 and indicators.iloc[-2]['macd_bar'] >= 0:
            macd_signal = "死叉，卖出信号"
        elif latest['macd_bar'] > 0:
            macd_signal = "MACD柱线为正，多头市场"
        else:
            macd_signal = "MACD柱线为负，空头市场"
        
        # 判断KDJ信号
        if latest['k'] < 20 and latest['d'] < 20:
            kdj_signal = "超卖区域，可能反弹"
        elif latest['k'] > 80 and latest['d'] > 80:
            kdj_signal = "超买区域，可能回调"
        elif latest['k'] > latest['d'] and indicators.iloc[-2]['k'] <= indicators.iloc[-2]['d']:
            kdj_signal = "KDJ金叉，买入信号"
        elif latest['k'] < latest['d'] and indicators.iloc[-2]['k'] >= indicators.iloc[-2]['d']:
            kdj_signal = "KDJ死叉，卖出信号"
        else:
            kdj_signal = "KDJ中性"
        
        # 判断RSI信号
        if latest['rsi6'] < 20:
            rsi_signal = "RSI严重超卖，可能反弹"
        elif latest['rsi6'] > 80:
            rsi_signal = "RSI严重超买，可能回调"
        elif 20 <= latest['rsi6'] < 50:
            rsi_signal = "RSI偏弱"
        else:
            rsi_signal = "RSI偏强"
        
        # 判断布林带信号
        current_price = latest['close']
        if current_price > latest['boll_up']:
            boll_signal = "价格突破布林上轨，超买区域"
        elif current_price < latest['boll_low']:
            boll_signal = "价格跌破布林下轨，超卖区域"
        else:
            boll_position = (current_price - latest['boll_low']) / (latest['boll_up'] - latest['boll_low'])
            if boll_position < 0.2:
                boll_signal = "价格接近布林下轨，可能反弹"
            elif boll_position > 0.8:
                boll_signal = "价格接近布林上轨，可能回调"
            else:
                boll_signal = "价格在布林带中轨附近，趋势不明确"
        
        # 生成支撑位和阻力位
        support_1 = min(indicators['low'].tail(10))
        support_2 = min(indicators['low'].tail(30))
        resistance_1 = max(indicators['high'].tail(10))
        resistance_2 = max(indicators['high'].tail(30))
        
        # 生成综合分析
        if trend == "上升趋势" and (macd_signal.startswith("金叉") or kdj_signal.startswith("KDJ金叉")):
            summary = "技术面看多，建议买入"
            confidence = "high"
        elif trend == "下降趋势" and (macd_signal.startswith("死叉") or kdj_signal.startswith("KDJ死叉")):
            summary = "技术面看空，建议卖出"
            confidence = "high"
        elif (trend == "上升趋势" and rsi_signal.endswith("可能回调")) or (trend == "下降趋势" and rsi_signal.endswith("可能反弹")):
            summary = "短期可能出现反转，建议观望"
            confidence = "medium"
        else:
            summary = "信号不明确，建议观望"
            confidence = "low"
        
        return {
            'stock_code': stock_code,
            'current_price': float(latest['close']),
            'date': latest['date'],
            'trend': trend,
            'macd_signal': macd_signal,
            'kdj_signal': kdj_signal,
            'rsi_signal': rsi_signal,
            'boll_signal': boll_signal,
            'support_levels': [float(support_1), float(support_2)],
            'resistance_levels': [float(resistance_1), float(resistance_2)],
            'indicators': {
                'ma5': float(latest['ma5']),
                'ma10': float(latest['ma10']),
                'ma20': float(latest['ma20']),
                'ma30': float(latest['ma30']),
                'ma60': float(latest['ma60']),
                'macd_dif': float(latest['macd_dif']),
                'macd_dea': float(latest['macd_dea']),
                'macd_bar': float(latest['macd_bar']),
                'k': float(latest['k']),
                'd': float(latest['d']),
                'j': float(latest['j']),
                'rsi6': float(latest['rsi6']),
                'rsi12': float(latest['rsi12']),
                'rsi24': float(latest['rsi24']),
                'boll_up': float(latest['boll_up']),
                'boll_mid': float(latest['boll_mid']),
                'boll_low': float(latest['boll_low'])
            },
            'summary': summary,
            'confidence': confidence
        } 